﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using System.Xml;
using UniRlv.Server;
using UniRlv.Utility;

namespace CheckCodes
{
    public partial class FrmMain : Form
    {
        string tym, pzwh, gg, batch, ratio, scrq;
        List<string> codes1, codes2, codes3, codes4;
        int tagLevel;
        int ratio21, ratio32, ratio43;
        FrmProcessBar progBar = null;

        private void FrmMain_FormClosed(object sender, FormClosedEventArgs e)
        {
            codes1.Clear();
            codes2.Clear();
            codes3.Clear();
            codes4.Clear();
        }

        public FrmMain()
        {
            InitializeComponent();
        }

        private void FrmMain_Load(object sender, EventArgs e)
        {
            codes1 = new List<string>();
            codes2 = new List<string>();
            codes3 = new List<string>();
            codes4 = new List<string>();

            string msg = "";

            try
            {
                object obj = SqlHelper.ExecuteScalar("select getdate()", ref msg);

                if (obj != null)
                {
                    AppendLog("当前数据库时间：" + obj.ToString());
                }


            }
            catch (Exception exp)
            {
                MessageBox.Show("数据库连接失败：" + exp.Message);
                Close();
                return;
            }

            string ver = string.Format(" V{0}.{1}.{2}",
                Assembly.GetExecutingAssembly().GetName().Version.Major,
                Assembly.GetExecutingAssembly().GetName().Version.Minor,
                Assembly.GetExecutingAssembly().GetName().Version.Build);
            this.Text += string.Format(" {0}", ver);
        }

        private void btnBrowse_Click(object sender, EventArgs e)
        {
            OpenFileDialog ofd = new OpenFileDialog();
            ofd.Filter = "(*.xml)入库文件|*.xml";
            if (ofd.ShowDialog() == DialogResult.OK)
            {
                this.Cursor = Cursors.WaitCursor;
                txtPath.Text = ofd.FileName;
                btnRun.Enabled = true;

                string log = GetInfo(txtPath.Text);

                if (!string.IsNullOrEmpty(log))
                {
                    AppendLog(log);
                }
                else
                {
                    AppendLog($"通用名={tym}，批准文号={pzwh}，批次号={batch}，规格={gg}，生产日期={scrq}，包装比例={ratio}，包装层级={tagLevel}");
                    txtBatch.Text = batch;
                    switch (tagLevel)
                    {
                        case 1:
                            AppendLog("一级码数量=" + codes1.Count);
                            break;
                        case 2:
                            AppendLog($"一级码数量={codes1.Count}，二级码数量={codes2.Count}");
                            break;
                        case 3:
                            AppendLog($"一级码数量={codes1.Count}，二级码数量={codes2.Count}，三级码数量={codes3.Count}");
                            break;
                        case 4:
                            AppendLog($"一级码数量={codes1.Count}，二级码数量={codes2.Count}，三级码数量={codes3.Count}，四级码数量={codes4.Count}");
                            break;
                        default:
                            break;
                    }
                }
                this.Cursor = Cursors.Default;
            }
        }

        private string GetInfo(string path)
        {
            try
            {

                XmlDocument doc = new XmlDocument();
                doc.Load(path);

                XmlNode xn = doc.SelectSingleNode("DataList");
                XmlElement ProductNode = xn.FirstChild as XmlElement;

                tym = ProductNode.GetAttribute("productName");
                pzwh = ProductNode.GetAttribute("pzwh");

                XmlElement batchNode = ProductNode.FirstChild as XmlElement;
                batch = batchNode.GetAttribute("batchNo");
                gg = batchNode.GetAttribute("specification");
                ratio = batchNode.GetAttribute("tagRatio");
                scrq = batchNode.GetAttribute("produceDate");

                tagLevel = GetTagLevel(ratio);
                int[] ratios = GetLevelRatios(ratio);

                codes1.Clear();
                codes2.Clear();
                codes3.Clear();
                codes4.Clear();

                int n1 = 0, n2 = 0, n3 = 0;

                switch (tagLevel)
                {
                    case 2:
                        ratio21 = ratios[0];

                        foreach (var item in batchNode.ChildNodes)
                        {
                            if (codes1.Count!=0 && codes1.Count%ratio21 == 0)
                            {
                                codes2.Add((item as XmlElement).GetAttribute("code"));
                            }
                            else
                            {
                                codes1.Add((item as XmlElement).GetAttribute("code"));
                            }
                        }

                        break;
                    case 3:
                        ratio32 = ratios[0];
                        ratio21 = ratios[1];

                        
                        foreach (var item in batchNode.ChildNodes)
                        {
                            if (n2!=0 && n2%ratio32 == 0)
                            {
                                codes3.Add((item as XmlElement).GetAttribute("code"));
                                n1 = 0;
                                n2 = 0;

                                continue;
                            }

                            if (n1!=0 && n1%ratio21 == 0)
                            {
                                codes2.Add((item as XmlElement).GetAttribute("code"));
                                n2++;
                                n1 = 0;
                            }
                            else
                            {
                                codes1.Add((item as XmlElement).GetAttribute("code"));
                                n1++;
                            }
                        }

                        break;
                    case 4:
                        ratio43 = ratios[0];
                        ratio32 = ratios[1];
                        ratio21 = ratios[2];

                        foreach (var item in batchNode.ChildNodes)
                        {
                            if (n3 != 0 && n3 % ratio43 == 0)
                            {
                                codes4.Add((item as XmlElement).GetAttribute("code"));
                                n1 = 0;
                                n2 = 0;
                                n3 = 0;
                                continue;
                            }

                            if (n2 != 0 && n2 % ratio32 == 0)
                            {
                                codes3.Add((item as XmlElement).GetAttribute("code"));
                                n1 = 0;
                                n2 = 0;

                                continue;
                            }

                            if (n1 != 0 && n1 % ratio21 == 0)
                            {
                                codes2.Add((item as XmlElement).GetAttribute("code"));
                                n2++;
                                n1 = 0;
                            }
                            else
                            {
                                codes1.Add((item as XmlElement).GetAttribute("code"));
                                n1++;
                            }
                        }

                        break;
                    default:
                        return "包装层级太高：" + ratio;
                }

                return "";

            }
            catch (Exception ex)
            {
                return ex.Message;
            }

        }

        private void btnRun_Click(object sender, EventArgs e)
        {
            if (string.IsNullOrEmpty(txtBatch.Text))
            {
                MessageBox.Show("批次号不能为空！");
                return;
            }

            this.backgroundWorker1.RunWorkerAsync(); // 运行 backgroundWorker 组件
            btnBrowse.Enabled = false;
            btnRun.Enabled = false;
            progBar = new FrmProcessBar(this.backgroundWorker1);// 显示进度条窗体
            progBar.Text = "查重进度";
            progBar.Show(this);
        }

        private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
            BackgroundWorker worker = sender as BackgroundWorker;
            string msg = "";

            //for (int i = 0; i <= 100; i++)
            //{
            //    Thread.Sleep(100);
            //    worker.ReportProgress(i, i.ToString() + "  你好！\r\n"); //注意：这里向子窗体返回信息值，这里是两个值，一个用于进度条，一个用于文本框的。
            //    if (worker.CancellationPending)  // 如果用户取消则跳出处理数据代码 
            //    {
            //        e.Cancel = true;
            //        break;
            //    }
            //}
            int total = codes1.Count + codes2.Count + codes3.Count + codes4.Count;
            int prog = 0;
            string batch = CallCtrlWithThreadSafety.GetText(txtBatch, this).Trim();
            string sql = "";
            int dup = 0;
            List<string> codes = new List<string>();


            int cnt = Convert.ToInt32(SqlHelper.ExecuteScalar($"select count(a.id) as qty from CodeInfo as a left join ProductionTask as b on a.taskID = b.id where b.batch = '{batch}'", ref msg));
            int pages = cnt == 0 ? 0 : (cnt - 1) / 1000 + 1;

            if (pages > 0)
            {
                for (int p = 1; p <= pages; p++)
                {
                    List<string> li = QueryCodeHistoryPageByBatch(p, 1000, batch, ref msg);

                    if (li!=null)
                    {
                        codes.AddRange(li);
                        worker.ReportProgress(p * 94 / pages, ".");
                    }
                    else
                    {
                        worker.ReportProgress(p * 94 / pages, msg);
                    }
                    
                }
            }

                
            worker.ReportProgress(93, $"加载历史数据{cnt}条\r\n");

            for (int i = 0; i < codes1.Count; i++)
            {
                if (codes.Contains(codes1[i]))
                {

                    worker.ReportProgress(i * 100 / total, $"一级码重复：{codes1[i]}, 位置：{GetPosition(i, 1)}\r\n");
                    dup++;
                    continue;
                }

                worker.ReportProgress(i*100/total);
            }

            prog += codes1.Count * 100 / total;
            worker.ReportProgress(prog, "一级码查重完毕\r\n");

            for (int i = 0; i < codes2.Count; i++)
            {
                if (codes.Contains(codes2[i]))
                {
                    worker.ReportProgress(i * 100 / total + prog, $"二级码重复：{codes2[i]}, 位置：{GetPosition(i, 2)}\r\n");
                    dup++;
                    continue;
                }

                worker.ReportProgress(i * 100 / total + prog);
            }

            prog += codes2.Count * 100 / total;
            worker.ReportProgress(prog, "二级码查重完毕\r\n");

            for (int i = 0; i < codes3.Count; i++)
            {
                if(codes.Contains(codes3[i]))
                {
                    worker.ReportProgress(i * 100 / total + prog, $"三级码重复：{codes3[i]}, 位置：{GetPosition(i, 3)}\r\n");
                    dup++;
                    continue;
                }

                worker.ReportProgress(i * 100 / total + prog);
            }

            prog += codes3.Count * 100 / total;
            worker.ReportProgress(prog, "三级码查重完毕\r\n");

            for (int i = 0; i < codes4.Count; i++)
            {
                if (codes.Contains(codes4[i]))
                {
                    worker.ReportProgress(i * 100 / total + prog, $"四级码重复：{codes4[i]}, 位置：{GetPosition(i, 4)}\r\n");
                    dup++;
                    continue;
                }

                worker.ReportProgress(i * 100 / total + prog);
            }

            prog += codes4.Count * 100 / total;
            worker.ReportProgress(prog, "四级码查重完毕");
            CallCtrlWithThreadSafety.SetText(lbTip, $"查重结果：查重总数{total}，重码数量{dup}", this);
        }

        private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            try
            {
                if (!string.IsNullOrEmpty(e.UserState as string))
                {
                    AppendLog(e.UserState.ToString());
                }

            }
            catch (Exception)
            {
            }
        }

        private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            progBar.Close();

            if (e.Result != null)
            {
                MessageBox.Show(e.Result.ToString());
            }
            else if (e.Cancelled)
            {
                MessageBox.Show("操作取消");
            }

            btnRun.Enabled = false;
            btnBrowse.Enabled = true;

            AppendLog("查重结束");
        }

        void AppendLog(string msg)
        {
            string s = $"[{DateTime.Now.ToString("HH:mm:ss")}] {msg}\r\n";
            CallCtrlWithThreadSafety.AppendText(txtLog, s, this);
        }

        public int GetTagLevel(string ratio)
        {
            return ratio.Split(new char[] { ':'}, StringSplitOptions.None).Length;
        }

        /// <summary>
        /// 四级关联的各级包装数量顺序ratio43,ratio32,ratio21,0
        /// 三级关联的各级包装数量顺序ratio32,ratio21,0
        /// 二级关联的各级包装数量顺序ratio21,0
        /// </summary>
        /// <param name="ratio"></param>
        /// <returns>数组长度等于包装级别</returns>
        public int[] GetLevelRatios(string ratio)
        {
            int[] ri = GetRatios(ratio);

            for (int i = 0; i < ri.Length - 1; i++)
            {
                ri[i] = ri[i + 1] / ri[i];
            }

            if (ri.Length > 1)
            {
                ri[ri.Length - 1] = 0;
            }

            return ri;
        }

        /// <summary>
        /// 返回比例数字，比如1:20，则返回 1和20
        /// </summary>
        /// <param name="ratio"></param>
        /// <returns>数组长度等于包装级别</returns>
        public static int[] GetRatios(string ratio)
        {
            string[] ss = ratio.Split(new char[] { ':' }, StringSplitOptions.None);
            int[] ri = new int[ss.Length];

            for (int i = 0; i < ss.Length; i++)
            {
                ri[i] = Convert.ToInt32(ss[i]);
            }

            return ri;
        }

        public string GetPosition(int pos, int level)
        {
            switch (tagLevel)
            {
                case 1:
                    return $"一级序号{pos+1}";
                case 2:
                    if (level == 1)
                    {
                        return $"一级总序号{pos+1}，二级序号{pos/ratio21 + 1}，包装内一级码序号{pos % ratio21 + 1}";
                    }
                    else
                    {
                        return $"二级序号{pos + 1}";
                    }
                case 3:
                    if (level == 1)
                    {
                        int pos2 = pos / ratio21;
                        return $"一级总序号{pos + 1}，三级序号{pos2 / ratio32 + 1}，二级包装内一级码序号{pos % ratio21 + 1}，三级包装内二级码序号{pos2 % ratio32 + 1}";
                    }
                    else if (level == 2)
                    {
                        return $"二级总序号{pos + 1}，三级序号{pos / ratio32 + 1}，包装内二级码序号{pos % ratio32 + 1}";
                    }
                    else
                    {
                        return $"三级序号{pos + 1}";
                    }
                case 4:
                    if (level == 1)
                    {
                        int pos2 = pos / ratio21;
                        int pos3 = pos2 / ratio32;
                        return $"一级总序号{pos + 1}，四级序号{pos3 / ratio43 + 1}，二级包装内一级码序号{pos % ratio21 + 1}，三级包装内二级码序号{pos2 % ratio32 + 1}，四级包装内三级码序号{pos3 % ratio43 + 1}";
                    }
                    else if (level == 2)
                    {
                        int pos3 = pos / ratio32;
                        return $"二级总序号{pos + 1}，四级序号{pos3 / ratio43 + 1}，三级包装内二级码序号{pos % ratio32 + 1}，四级包装内三级码序号{pos3 % ratio43 + 1}";
                    }
                    else if (level == 3)
                    {
                        return $"三级总序号{pos + 1}，四级序号{pos / ratio43 + 1}，包装内三级码序号{pos % ratio32 + 1}";
                    }
                    else
                    {
                        return $"四级序号{pos + 1}";
                    }
                default:
                    return "";
            }
        }

        public List<string> QueryCodeHistoryPageByBatch(int page, int pageSize, string batch, ref string msg)
        {
            string sql = string.Format("SELECT b.rowNum, a.code FROM {0} a, (SELECT TOP {1} row_number() OVER (ORDER BY c.ID DESC) rowNum, c.ID FROM {2} c join ProductionTask d on c.taskID = d.id where d.batch={4}) b WHERE a.ID = b.ID AND b.rowNum > {3} ORDER BY b.rowNum ASC",
                "CodeInfo", (page) * pageSize, "CodeInfo", (page - 1) * pageSize, batch);

            string errDesc = "";

            DataTable dt = SqlHelper.ExecuteTable(sql, ref errDesc);

            if (dt != null)
            {

                List<string> codes = new List<string>();
                foreach (DataRow dr in dt.Rows)
                {
                    codes.Add(dr["code"].ToString());
                }

                return codes;
            }
            else
            {
                msg = "查询历史数据出错：" + errDesc;
                return null;
            }
        }
    }
}
